// 引用 给变量起别名 数据类型 &别名 = 原名
// 注意 引用必须要初始化，在初始化后不可改变 从一而终
// 用引用做函数参数时，利用引用让形参修饰实参，可以简化指针修改实参
// 引用做函数返回值时，不要返回局部变量的地址
// 用const 修饰

#include <iostream>
using namespace std;

void base_use(); // 引用的基本使用
void as_func_params();  // 引用做函数参数
void const_reference();  // 常量引用

// 值传递
void my_swap01(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
}

// 地址传递
void my_swap02(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 引用传递
void my_swap03(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}

void base_use()
{
    cout << "reference base use..." << endl;
    int a = 10;
    //int &b;  // 这是错误的，必须要初始化
    int &b = a;  // 本质是转换成 int* const b = &a  是一个常量指针
    cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	b = 100;  // 这是赋值操作 不是更改

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}


void as_func_params()
{
    cout << "reference as func params..." << endl;
    int a = 1;
    int b = 2;

    // 值传递
    cout << "before call my_swap01 a = " << a << " b = " << b << endl;
    my_swap01(a, b);
    cout << "after call my_swap01 a = " << a << " b = " << b << "\n" << endl;

    // 传指针
    cout << "before call my_swap02 a = " << a << " b = " << b << endl;
    my_swap02(&a, &b);
    cout << "after call my_swap02 a = " << a << " b = " << b << "\n" <<endl;

    // 传引用
    // 通过引用参数产生的效果同按地址传递是一样的。引用的语法更清楚简单
    cout << "before call my_swap03 a = " << a << " b = " << b << endl;
    my_swap03(a, b);
    cout << "after call my_swap03 a = " << a << " b = " << b << "\n" <<endl;

}

void const_reference()
{
    cout << "const reference..." << endl;
    
    // int &a = 10; // 这是错误的，引用本身需要一个合法的内存空间
    const int &a = 10;  // 这是允许的，编译器会把代码优化为 int temp = 10; const int& a = temp;
    cout << "a = " << a << endl;

    // a = 100; // const 不允许修改
    // 函数中利用常量引用防止误操作修改实参  void func(const int& a, const int& b) {};
}

int main()
{
    base_use();
    as_func_params();
    const_reference();
    return 0;
}